<?php

namespace app\service;

use app\core\Constant;
use app\core\exception\BusinessException;
use app\core\Request;
use app\core\Service;
use app\core\util\Random;
use app\core\util\Tree;
use app\model\SysMenu;
use app\model\SysRoleMenu;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Cache;
use think\facade\Db;

/**
 * @extends Service<MenuService>
 */
class MenuService extends Service
{
    public function getSysMenuList($appKey, $searchQuery = null)
    {
        $menus = SysMenu::where('app_key', $appKey)
            ->where(function ($q) use ($searchQuery) {
                if (!empty($searchQuery)) {
                    if (!empty($searchQuery['menu_name'])) {
                        $q = $q->where('menu_name', 'like', "%" . $searchQuery['menu_name'] . "%");
                    }
                    if (!empty($searchQuery['status'])) {
                        $q->where('status', $searchQuery['status']);
                    }
                }
            });

        $pid = $menus->order('parent_id asc')->value('parent_id');
        $list = $menus->order("order_num desc")->select()->toArray();

        if (count($list) > 0 && empty($searchQuery['menu_name'])) {
            $list = Tree::invoke()->buildTree($list, $pid, 'menu_id');
        }

        return $list;
    }

    /**
     * 获取菜单
     * @return array|false|string
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getMenus($appKey)
    {
        $key = "menus";
//        $cacheMenus = Cache::get($key);

        if (empty($cacheMenus)) {
            $menus = SysMenu::where('app_key', $appKey)
                ->where('status', Constant::STATUS_NORMAL)
                ->select();
            $menus->load(['roles']);
            $menus = $menus->toArray();
            if (!empty($menus)) {
                // 缓存菜单
                Cache::set($key, json_encode($menus), 30 * 86400);
            }
        } else {
            $menus = json_decode($cacheMenus, JSON_UNESCAPED_UNICODE);
        }
        $data = $this->buildMenuTree($menus, 0);
        return $data;
    }

    /**
     * @param $arr
     * @param int $id
     * @return mixed
     */
    private function buildMenuTree($arr, int $id = 0)
    {
        $tree = $this->findMenuChild($arr, $id);

        if (count($tree) <= 0) {
            return [];
        }

        foreach ($tree as $k => $menu) {
            $child = $this->buildMenuTree($arr, $menu['menu_id']);
            if (count($child) > 0) {
                $tree[$k]['children'] = $child;
            }
        }

        return $tree;
    }

    /**
     * @param $arr
     * @param $pid
     * @return mixed
     */
    private function findMenuChild($arr, $pid)
    {
        $child = [];
        foreach ($arr as $menu) {
            if ($menu['parent_id'] == $pid) {
                $roles = array_column($menu['roles'], 'role_key');
//                if (Request::invoke()->isSuperAdmin()) {
//                    $roles = array_merge(['admin'], $roles);
//                }
                $child[] = [
                    "menu_id" => $menu['menu_id'],
                    "parent_id" => $menu['parent_id'],
                    "path" => $menu['path'],
                    "name" => $menu['route_name'],
                    "component" => $menu['component'],
                    "meta" => [
                        "layout" => $menu['layout'], // none | DefaultLayout | PageLayout
                        'query' => $menu['query'], // 页面参数
                        "roles" => $roles, // 配置能访问该页面的角色，如果不匹配，则会被禁止访问该路由页面
                        "icon" => $menu['icon'], // 菜单配置 icon
                        "locale" => $menu['locale'], // 菜单名（语言包键名）
                        "visible" => $menu['visible'] == Constant::VISIBLE, // 是否显示左侧菜单
                        'menuType' => $menu['menu_type'], // 菜单类型 菜单类型（0目录 1菜单）
                        "order" => $menu['order_num'], // 排序路由菜单项。如果设置该值，值越高，越靠前
                        "isCache" => $menu['is_cache'] == Constant::IS_CACHE, // 页面是否缓存
                        'isFrame' => $menu['is_frame'] == Constant::IS_FRAME, // 是否外链
                    ]
                ];
            }
        }

        return $child;
    }

    public function getMenuInfo($id): array
    {
        $menu = SysMenu::find($id);
        if (!$menu) {
            throw new BusinessException('菜单不存在');
        }
        return $menu->toArray();
    }

    public function save($data, $id = null)
    {
        $saveData = [
            'menu_name' => $data['menu_name'],
            'parent_id' => $data['parent_id'] ?? 0,
            'app_key' => $data['app_key'],
            'order_num' => $data['order_num'] ?? 0,
            'locale' => $data['locale'] ?? null,
            'path' => $data['path'] ?? null,
            'component' => $data['component'] ?? null,
            'query' => $data['query'] ?? null,
            'layout' => $data['layout'] ?? null,
            'visible' => $data['visible'] ?? Constant::VISIBLE,
            'status' => $data['status'] ?? Constant::STATUS_NORMAL,
            'is_cache' => $data['is_cache'] ?? Constant::IS_CACHE,
            'is_frame' => $data['is_frame'] ?? Constant::NO_FRAME,
            'perms' => $data['perms'],
            'menu_type' => $data['menu_type'] ?? Constant::MENU_DIR,
            'icon' => $data['icon'] ?? null,
            'remark' => $data['remark'] ?? null,
        ];

        if (!empty($id)) {
            if ($saveData['parent_id'] == $id) {
                throw new BusinessException("上级菜单不能选择自己");
            }
            $menu = SysMenu::where('menu_id', $id)->find();
            if (!$menu) {
                throw new BusinessException("菜单不存在");
            }
            if ($saveData['perms'] != $menu['perms']){
                $this->checkPermsUnique($saveData['perms']);
            }
            $menu->save($saveData);
        } else {
            if (!empty($saveData['perms'])) {
                $this->checkPermsUnique($saveData['perms']);
            }
            $saveData['route_name'] = Random::alpha();
            SysMenu::create($saveData);
        }

        Cache::delete("menus");

        return true;
    }

    /**
     * @param $perms
     * @return bool
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function checkPermsUnique($perms): bool
    {
        if (SysMenu::where('perms', $perms)->find()){
            throw new BusinessException('权限标识已存在');
        }
        return true;
    }

    public function getMenuTree($appKey)
    {
        $menus = SysMenu::where('status', Constant::STATUS_NORMAL)
            ->where('app_key', $appKey)
            ->field("menu_id as `key`, menu_name as `title`, parent_id")
            ->select()->toArray();
        return Tree::invoke()->buildTree($menus, 0, 'key');
    }

    public function delById($id)
    {
        $hasChild = SysMenu::where('parent_id', $id)->find();
        if ($hasChild) {
            throw new BusinessException("存在子级菜单无法删除");
        }
        $menu = SysMenu::where('menu_id', $id)->find();
        if (!$menu) {
            throw new BusinessException("菜单不存在");
        }

        Db::startTrans();
        try {
            $menu->delete();
            // 关联删除
            SysRoleMenu::where('menu_id', $id)->delete();
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            throw new BusinessException($e->getMessage());
        }

        Cache::delete("menus");
    }
}